const { spawn } = require('child_process')
// const debounce = require('lodash.debounce')
var log4js = require('log4js');
var os = require('os')


log4js.configure({
  appenders: {
    fileout: { type: "file", filename: "C:\\Users\\ldsb\\Documents\\NodejsProject\\test0\\server\\fileout.log" },
    datafileout: {
      type: "dateFile",
      filename: "datafileout.log",
      pattern: ".yyyy-MM-dd"
    },
    consoleout: { type: "console" },
  },
  categories: {
    default: { appenders: ["fileout"], level: "debug" },
    anything: { appenders: ["consoleout"], level: "debug" }
  }
});

let logger = log4js.getLogger('default');
logger.debug(os.platform())
const pythonScriptPath = 'C:\\Users\\ldsb\\Documents\\NodejsProject\\test0\\server\\cycle.py'

const pins = [{
  port: 1,
  address: 0xA00,
  bit: 0
}, {
  port: 2,
  address: 0xA07,
  bit: 1
}, {
  port: 3,
  address: 0xA01,
  bit: 3
}, {
  port: 4,
  address: 0xA03,
  bit: 0
}, {
  port: 6,
  address: 0xA03,
  bit: 2
}, {
  port: 7,
  address: 0xA04,
  bit: 4
}, {
  port: 8,
  address: 0xA04,
  bit: 1
}, {
  port: 9,
  address: 0xA03,
  bit: 4
}]

const configureInterruptHandler = gpio => {
  const pollerEventHandler = (callback) => {
    console.log('enter')
    // console.log('status: ',typeof gpio._workprocess)
    gpio.read((err, value) => {
      if (Date.now() > gpio._timeStamp) {
        // console.log('oldvalue: ', gpio._value, Date.now())
        // console.log('newvalue: ', value, Date.now())
        logger.debug(`${Date.now()}-- ${gpio._gpio}--value:${value}`)
        gpio._timeStamp = Date.now()
        if (value != null && gpio._value != null && gpio._value != value) {
          if ((value && gpio._risingEnabled) ||
            (!value && gpio._fallingEnabled))
            if (gpio._debounceTimeout > 0) {
              db(err, value)
            } else {
              gpio._listeners.forEach(cb => {
                cb(err, value)
              })
            }
          gpio._value = value
        }
      }
      if (callback) callback()
    })
  }
  const db = debounce((err, value) => {
    gpio._listeners.forEach(callback => {
      callback(err, value)
    })
  }, gpio._debounceTimeout)

  // function fn() {
  //   setTimeout(() => {
  //     pollerEventHandler(() => { fn() })
  //   }, 50)//监听轮询间隔50ms
  // }

  // fn()
  gpio._isCycle = true;
  setInterval(() => {
    pollerEventHandler()
  }, 1000)
}


class Gpio {
  //构造
  constructor(gpio, direction, edge, options) {
    if (typeof edge === 'object' && !options) {
      options = edge;
      edge = 'both';
    }

    options = options || {};
    this._gpio = typeof gpio == Number ? gpio : Number(gpio)
    this._direction = direction;
    this._edge = edge;
    this._pin = pins.filter(p => p.port == this._gpio)[0];
    this._debounceTimeout = options.debounceTimeout || 0;
    if (direction == 'in')
      this._value = true;
    else if (direction == 'out')
      this._value = false;
    this._listeners = [];
    this._timeStamp = 0;
    this._isCycle = false;
    this._workprocess = spawn('python', [pythonScriptPath])
    this._sendObj = {
      operation: "",
      port: {
        address: 0,
        bit: 0
      },
      value: false
    }

    // if (edge && direction === 'in') {
    //   this._risingEnabled = edge === 'both' || edge === 'rising';
    //   this._fallingEnabled = edge === 'both' || edge === 'falling';
    //   configureInterruptHandler(this)
    // }
  }

  //读
  read(callback) {
    //读操作
    const readValue = callback => {
      this._sendObj.operation = 'read'
      this._sendObj.port.address = this._pin.address
      this._sendObj.port.bit = this._pin.bit
      var sendstr = JSON.stringify(this._sendObj)
      sendstr = sendstr + '\n'
      //流输入
      this._workprocess.stdin.write(sendstr, (err) => {
        if (!err)
          //流输出
          this._workprocess.stdout.once('data', (data) => {
            // console.log(data.toString())
            try {
              var recvObj = JSON.parse(data.toString())
            } catch (error) {
              console.log(data.toString())
              throw new Error('数据格式error')
            }
            callback(null, recvObj.value)
          })
        else
          console.log('wirte error: ', err)
      })
    }

    if (callback)
      readValue(callback)
    else
      return new Promise((resolve, reject) => {
        readValue((err, value) => {
          if (err) {
            reject(err);
          } else {
            resolve(value);
          }
        });
      })
  }

  //写
  write(value, callback) {
    //写操作
    const writeValue = (value, callback) => {
      this._sendObj.operation = 'write'
      this._sendObj.port.address = this._pin.address
      this._sendObj.port.bit = this._pin.bit
      this._sendObj.value = value
      var sendstr = JSON.stringify(this._sendObj)
      sendstr = sendstr + '\n'
      this._workprocess.stdin.write(sendstr, (err) => {
        if (!err)
          this._workprocess.stdout.once('data', (data) => {
            // console.log('from py msg: ' + data)
            var recvObj = JSON.parse(data.toString())
            callback(null, recvObj.value)
          })
      })
    }
    if (callback)
      writeValue(value, callback)
    else
      return new Promise((resolve, reject) => {
        writeValue(value, err => {
          if (err) {
            reject(err);
          } else {
            resolve();
          }
        });
      })
  }

  //注册监听
  watch(callback) {
    this._listeners.push(callback);
    if (!this._isCycle && this._edge) {
      this._risingEnabled = this._edge === 'both' || this._edge === 'rising';
      this._fallingEnabled = this._edge === 'both' || this._edge === 'falling';
      configureInterruptHandler(this)
    }
  }

  //删除监听
  unwatch(callback) {
    if (this._listeners.length > 0) {
      if (typeof callback !== 'function') {
        this._listeners = [];
      } else {
        this._listeners = this._listeners.filter(listener => {
          return callback !== listener;
        });
      }
    }
  }
}


function debounce(func, wait) {
  var lastCallTime // 最后一次触法事件的时间
  var lastThis // 作用域
  var lastArgs // 参数
  var timerId // 定时器对象

  // 启动定时器
  function startTimer(timerExpired, wait) {
    return setTimeout(timerExpired, wait)
  }

  // function remainingWait(time) {
  //     const timeSinceLastCall = time - lastCallTime
  //     const timeWaiting = wait - timeSinceLastCall
  //     return timeWaiting
  // }

  // 调用func函数的判定条件 
  function shoudInvoking(time) {
    return lastCallTime !== undefined && (time - lastCallTime >= wait)
  }

  //  定时器的回调函数 
  function timerExpired() {
    const time = Date.now()
    if (shoudInvoking(time)) {
      return invokeFunc()
    }
    timerId = startTimer(timerExpired, wait)
  }

  // func函数执行   
  function invokeFunc() {
    timerId = undefined
    const args = lastArgs
    const thisArg = lastThis
    let result = func.apply(thisArg, args)
    lastArgs = lastThis = undefined
    return result
  }

  // 要返回的函数
  function debounced(...args) {
    // console.log('test111');
    let time = Date.now()
    lastThis = this
    lastArgs = args
    lastCallTime = time
    if (timerId === undefined) {
      timerId = startTimer(timerExpired, wait)
    }
  }

  return debounced
}


module.exports.Gpio = Gpio;